package com.longteng.testng.binder;

import com.beust.jcommander.internal.Lists;
import com.longteng.common.ClassFilter;
import com.longteng.common.ClassFinder;
import com.longteng.testng.DefaultValueTransfer;
import com.longteng.testng.MethodParam;
import com.longteng.testng.ValueTransfer;
import com.longteng.testng.annotation.Binding;
import com.longteng.testng.param.MethodParams;
import com.longteng.testng.param.Pair;
import com.longteng.testng.param.Row;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.longteng.common.ClassFilter.withAnnotation;
import static com.longteng.common.ClassFilter.withInherit;

/**
 * Created by sky on 15-12-23
 */
public class Binder {

    private List<BindPlugin> plugins = Lists.newArrayList();

    private ValueTransfer valueTranfer;

    public Binder(){
        this.valueTranfer= new DefaultValueTransfer();
        loadPlugins();
    }

    public Object[] bind(Row row, Method method) {
        MethodParam[] parameters = MethodParams.parse(method);
        List<Object> objects = Lists.newArrayList();
        Arrays.asList(parameters).stream().forEach(it -> {
            Optional<BindPlugin> optional = plugins.stream()
                    .filter(plugin -> plugin.filter(it))
                    .findFirst();
            if(optional.isPresent()){
                List<Pair> pairs = row.getPairs().parallelStream().filter(pair ->pair.getKey().startsWith(it.getName()))
                        .collect(Collectors.toList());
                if(pairs==null||pairs.size()==0){
                    throw new RuntimeException("未发现对应的参数,param:"+it.getName());
                }
                pairs.forEach(pair -> pair.setValue(this.valueTranfer.transfer(pair.getValue())));
                objects.add(optional.get().transfer(pairs,it));
            }
        });
        return objects.toArray();
    }

    private void loadPlugins(){
        Set<Class<?>> classes = ClassFinder.finder().filter(ClassFilter
                .filter(withAnnotation(Binding.class).and(withInherit(BindPlugin.class))))
                .find();
        classes.forEach(it -> {
            try {
                plugins.add((BindPlugin) it.newInstance());
            } catch (Exception e) {
                e.printStackTrace();
                // do nothing
            }
        });
    }

    public List<BindPlugin> getPlugins() {
        return plugins;
    }

    public void setPlugins(List<BindPlugin> plugins) {
        this.plugins = plugins;
    }

    public ValueTransfer getValueTranfer() {
        return valueTranfer;
    }

    public void setValueTranfer(ValueTransfer valueTransfer) {
        this.valueTranfer = valueTransfer;
    }
}
